/*
 * FileName:       N55P242.c
 * Author:         Kingsea  Version: v1.0.0  Date: 2018-11-16
 * Description:    
 * History:        
 *     <author>       <version>        <time>        <desc>
 *     Kingsea       v1.0.0        2018-11-16    
 */
#include "nordic_common.h"
#include "app_error.h"
#include "nrf_gpio.h"
#include "nrf_drv_spi.h"
#include "N55P242.h"
/****************************************************/
#if NRF_MODULE_ENABLED(SPI)
//////////////////////////////////////////////////////////////////////////
#define SPI_INSTANCE  0 /**< SPI instance index. */
static const nrf_drv_spi_t spi = NRF_DRV_SPI_INSTANCE(SPI_INSTANCE);  /**< SPI instance. */

static uint8_t       m_tx_buf[2];                        /**< TX buffer. */
static uint8_t       m_rx_buf[sizeof(m_tx_buf)];         /**< RX buffer. */
static const uint8_t m_length = sizeof(m_tx_buf);        /**< Transfer length. */
/**
 * @brief SPI user init.
 * @param none
 */
static void spi_init(uint8_t sck_pin, uint8_t mosi_pin, uint8_t miso_pin, uint8_t ss_pin)
{
    ret_code_t err_code;
    nrf_drv_spi_config_t spi_config = NRF_DRV_SPI_DEFAULT_CONFIG;
    spi_config.ss_pin   = ss_pin;
    spi_config.miso_pin = miso_pin;
    spi_config.mosi_pin = mosi_pin;
    spi_config.sck_pin  = sck_pin;
    spi_config.frequency= (nrf_drv_spi_frequency_t)SPI_DEFAULT_FREQUENCY;
    err_code = nrf_drv_spi_init(&spi, &spi_config, NULL, NULL);
    APP_ERROR_CHECK(err_code);
}

//////////////////////////////////////////////////////////////////////////
void N55P_SPI_WRITE_N55P242(uint8_t u8Reg, uint8_t u8Data)
{
    m_tx_buf[0] = u8Reg|0x80;
    m_tx_buf[1] = u8Data;
    APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, m_tx_buf, m_length, m_rx_buf, m_length));
}

uint8_t N55P_SPI_READ_N55P242(uint8_t u8Reg)
{
    m_tx_buf[0] = u8Reg;
    APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, m_tx_buf, m_length, m_rx_buf, m_length));
    return m_rx_buf[1];
}

void N55P__242_Init(uint8_t u8Dev, uint8_t sck_pin, uint8_t mosi_pin, uint8_t miso_pin, uint8_t ss_pin)
{
    spi_init(sck_pin, mosi_pin, miso_pin, ss_pin);
    N55P_SPI_WRITE_N55P242(N55P_RESET,0xff);
    if(u8Dev==N55P__242_Dev0)
        N55P_SPI_WRITE_N55P242(N55P_DVSL0,0xff);
    else
        N55P_SPI_WRITE_N55P242(N55P_DVSL1,0xff);        
}

int8_t N55P_Set1PinInputFloating(uint8_t u8Port, uint8_t u8Pin)
{
    if(u8Port>=N55P__242_PORTAMOUNT||u8Pin>=N55P__242_PORTPINAMOUNT)
        return -1;
    else
    {
        switch(u8Port)
        {
            case N55P__242_PA:
                N55P_SPI_WRITE_N55P242(N55P_NDIRA,~(0x01<<u8Pin));//set Direction=0
                N55P_SPI_WRITE_N55P242(N55P_NATTA,~(0x01<<u8Pin));//set Attribute=0
                N55P_SPI_WRITE_N55P242(N55P_NBUFA,~(0x01<<u8Pin));//set Buffer=0
                break;
                
            case N55P__242_PB:
                N55P_SPI_WRITE_N55P242(N55P_NDIRB,~(0x01<<u8Pin));//set Direction=0
                N55P_SPI_WRITE_N55P242(N55P_NATTB,~(0x01<<u8Pin));//set Attribute=0
                N55P_SPI_WRITE_N55P242(N55P_NBUFB,~(0x01<<u8Pin));//set Buffer=0
                break;
                
            case N55P__242_PC:
                N55P_SPI_WRITE_N55P242(N55P_NDIRC,~(0x01<<u8Pin));//set Direction=0
                N55P_SPI_WRITE_N55P242(N55P_NATTC,~(0x01<<u8Pin));//set Attribute=0
                N55P_SPI_WRITE_N55P242(N55P_NBUFC,~(0x01<<u8Pin));//set Buffer=0                
                break;
        }

        return 0;
    }
}

int8_t N55P_Set1PinInputPullHigh(uint8_t u8Port, uint8_t u8Pin)
{
    if(u8Port>=N55P__242_PORTAMOUNT||u8Pin>=N55P__242_PORTPINAMOUNT)
        return -1;
    else
    {
        switch(u8Port)
        {
            case N55P__242_PA:
                N55P_SPI_WRITE_N55P242(N55P_NDIRA,~(0x01<<u8Pin));//set Direction=0
                N55P_SPI_WRITE_N55P242(N55P_NATTA,~(0x01<<u8Pin));//set Attribute=0
                N55P_SPI_WRITE_N55P242(N55P_OBUFA,(0x01<<u8Pin));//set Buffer=1
                break;
                
            case N55P__242_PB:
                N55P_SPI_WRITE_N55P242(N55P_NDIRB,~(0x01<<u8Pin));//set Direction=0
                N55P_SPI_WRITE_N55P242(N55P_NATTB,~(0x01<<u8Pin));//set Attribute=0
                N55P_SPI_WRITE_N55P242(N55P_OBUFB,(0x01<<u8Pin));//set Buffer=1
                break;
                
            case N55P__242_PC:
                N55P_SPI_WRITE_N55P242(N55P_NDIRC,~(0x01<<u8Pin));//set Direction=0
                N55P_SPI_WRITE_N55P242(N55P_NATTC,~(0x01<<u8Pin));//set Attribute=0
                N55P_SPI_WRITE_N55P242(N55P_OBUFC,(0x01<<u8Pin));//set Buffer=1                
                break;
        }

        return 0;
    }
}

int8_t N55P_Set1PinInputPullLow(uint8_t u8Port, uint8_t u8Pin)
{
    if(u8Port>=N55P__242_PORTAMOUNT||u8Pin>=N55P__242_PORTPINAMOUNT)
        return -1;
    else
    {
        switch(u8Port)
        {
            case N55P__242_PA:
                N55P_SPI_WRITE_N55P242(N55P_NDIRA,~(0x01<<u8Pin));//set Direction=0
                N55P_SPI_WRITE_N55P242(N55P_OATTA,(0x01<<u8Pin));//set Attribute=1
                N55P_SPI_WRITE_N55P242(N55P_OBUFA,(0x01<<u8Pin));//set Buffer=1
                break;
                
            case N55P__242_PB:
                N55P_SPI_WRITE_N55P242(N55P_NDIRB,~(0x01<<u8Pin));//set Direction=0
                N55P_SPI_WRITE_N55P242(N55P_OATTB,(0x01<<u8Pin));//set Attribute=1
                N55P_SPI_WRITE_N55P242(N55P_OBUFB,(0x01<<u8Pin));//set Buffer=1
                break;
                
            case N55P__242_PC:
                N55P_SPI_WRITE_N55P242(N55P_NDIRC,~(0x01<<u8Pin));//set Direction=0
                N55P_SPI_WRITE_N55P242(N55P_OATTC,(0x01<<u8Pin));//set Attribute=1
                N55P_SPI_WRITE_N55P242(N55P_OBUFC,(0x01<<u8Pin));//set Buffer=1                
                break;
        }

        return 0;
    }
}

int8_t N55P_Set1PinHigh(uint8_t u8Port, uint8_t u8Pin)
{
    if(u8Port>=N55P__242_PORTAMOUNT||u8Pin>=N55P__242_PORTPINAMOUNT)
        return -1;
    else
    {
        switch(u8Port)
        {
            case N55P__242_PA:
                N55P_SPI_WRITE_N55P242(N55P_ODIRA,(0x01<<u8Pin));//set Direction=1
            
                if((N55P_SPI_READ_N55P242(N55P_ATTA)&(0x01<<u8Pin))==(0x01<<u8Pin))//if Attribute=1
                    N55P_SPI_WRITE_N55P242(N55P_NBUFA,~(0x01<<u8Pin));//set Buffer=0
                else//if Attribute=0
                    N55P_SPI_WRITE_N55P242(N55P_OBUFA,(0x01<<u8Pin));//set Buffer=1
                
                break;
                
            case N55P__242_PB:
                N55P_SPI_WRITE_N55P242(N55P_ODIRB,(0x01<<u8Pin));//set Direction=1
            
                if((N55P_SPI_READ_N55P242(N55P_ATTB)&(0x01<<u8Pin))==(0x01<<u8Pin))//if Attribute=1
                    N55P_SPI_WRITE_N55P242(N55P_NBUFB,~(0x01<<u8Pin));//set Buffer=0
                else//if Attribute=0
                    N55P_SPI_WRITE_N55P242(N55P_OBUFB,(0x01<<u8Pin));//set Buffer=1
                
                break;
                
            case N55P__242_PC:
                N55P_SPI_WRITE_N55P242(N55P_ODIRC,(0x01<<u8Pin));//set Direction=1
            
                if((N55P_SPI_READ_N55P242(N55P_ATTC)&(0x01<<u8Pin))==(0x01<<u8Pin))//if Attribute=1
                    N55P_SPI_WRITE_N55P242(N55P_NBUFC,~(0x01<<u8Pin));//set Buffer=0
                else//if Attribute=0
                    N55P_SPI_WRITE_N55P242(N55P_OBUFC,(0x01<<u8Pin));//set Buffer=1        
                
                break;
        }

        return 0;
    }
}

int8_t N55P_Set1PinLow(uint8_t u8Port, uint8_t u8Pin)
{
    if(u8Port>=N55P__242_PORTAMOUNT||u8Pin>=N55P__242_PORTPINAMOUNT)
        return -1;
    else
    {
        switch(u8Port)
        {
            case N55P__242_PA:
                N55P_SPI_WRITE_N55P242(N55P_ODIRA,(0x01<<u8Pin));//set Direction=1
            
                if((N55P_SPI_READ_N55P242(N55P_ATTA)&(0x01<<u8Pin))==(0x01<<u8Pin))//if Attribute=1
                    N55P_SPI_WRITE_N55P242(N55P_OBUFA,(0x01<<u8Pin));//set Buffer=1            
                else//if Attribute=0
                    N55P_SPI_WRITE_N55P242(N55P_NBUFA,~(0x01<<u8Pin));//set Buffer=0
                
                break;
                
            case N55P__242_PB:
                N55P_SPI_WRITE_N55P242(N55P_ODIRB,(0x01<<u8Pin));//set Direction=1
            
                if((N55P_SPI_READ_N55P242(N55P_ATTB)&(0x01<<u8Pin))==(0x01<<u8Pin))//if Attribute=1
                    N55P_SPI_WRITE_N55P242(N55P_OBUFB,(0x01<<u8Pin));//set Buffer=1            
                else//if Attribute=0
                    N55P_SPI_WRITE_N55P242(N55P_NBUFB,~(0x01<<u8Pin));//set Buffer=0
                
                break;
                
            case N55P__242_PC:    
                N55P_SPI_WRITE_N55P242(N55P_ODIRC,(0x01<<u8Pin));//set Direction=1
            
                if((N55P_SPI_READ_N55P242(N55P_ATTC)&(0x01<<u8Pin))==(0x01<<u8Pin))//if Attribute=1
                    N55P_SPI_WRITE_N55P242(N55P_OBUFC,(0x01<<u8Pin));//set Buffer=1            
                else//if Attribute=0
                    N55P_SPI_WRITE_N55P242(N55P_NBUFC,~(0x01<<u8Pin));//set Buffer=0
                
                break;
        }

        return 0;
    }
}

int8_t N55P_Set1PinPWM(uint8_t u8Port, uint8_t u8Pin, uint8_t u8Attribut,uint8_t u8Duty)
{
    if(u8Port>=N55P__242_PORTAMOUNT||u8Pin>=N55P__242_PORTPINAMOUNT)
        return -1;
    else
    {
        switch(u8Port)
        {
            case N55P__242_PA:
                N55P_SPI_WRITE_N55P242(N55P_ODIRA,(0x01<<u8Pin));//set Direction=1
            
                if(u8Attribut==N55P_HIGH)
                    N55P_SPI_WRITE_N55P242(N55P_OATTA,(0x01<<u8Pin));//set Attribute=1                    
                else
                    N55P_SPI_WRITE_N55P242(N55P_NATTA,~(0x01<<u8Pin));//set Attribute=0
                
                N55P_SPI_WRITE_N55P242(N55P_PWMA0+u8Pin,u8Duty);//set PWM Duty Cycle
                N55P_SPI_WRITE_N55P242(N55P_PWMEA,(N55P_SPI_READ_N55P242(N55P_PWMEA)|(0x01<<u8Pin)));//set PWM Enalbe                
                break;
                
            case N55P__242_PB:
                N55P_SPI_WRITE_N55P242(N55P_ODIRB,(0x01<<u8Pin));//set Direction=1
            
                if(u8Attribut==N55P_HIGH)
                    N55P_SPI_WRITE_N55P242(N55P_OATTB,(0x01<<u8Pin));//set Attribute=1                    
                else
                    N55P_SPI_WRITE_N55P242(N55P_NATTB,~(0x01<<u8Pin));//set Attribute=0
                
                N55P_SPI_WRITE_N55P242(N55P_PWMB0+u8Pin,u8Duty);//set PWM Duty Cycle
                N55P_SPI_WRITE_N55P242(N55P_PWMEB,(N55P_SPI_READ_N55P242(N55P_PWMEB)|(0x01<<u8Pin)));//set PWM Enalbe                    
                break;
                
            case N55P__242_PC:    
                N55P_SPI_WRITE_N55P242(N55P_ODIRC,(0x01<<u8Pin));//set Direction=1
            
                if(u8Attribut==N55P_HIGH)
                    N55P_SPI_WRITE_N55P242(N55P_OATTC,(0x01<<u8Pin));//set Attribute=1                    
                else
                    N55P_SPI_WRITE_N55P242(N55P_NATTC,~(0x01<<u8Pin));//set Attribute=0
                
                N55P_SPI_WRITE_N55P242(N55P_PWMC0+u8Pin,u8Duty);//set PWM Duty Cycle
                N55P_SPI_WRITE_N55P242(N55P_PWMEC,(N55P_SPI_READ_N55P242(N55P_PWMEC)|(0x01<<u8Pin)));//set PWM Enalbe                        
                break;
        }

        return 0;
    }    
}

int8_t N55P_SetPWMClkDivider(uint8_t u8Group, uint8_t u8Divider)
{
    if(u8Group > N55P_CKC_PC47 || u8Divider > N55P_FOSC1_32)
        return -1;
    else
    {
        switch(u8Group)
        {
            case N55P_CKA_PA03:
                N55P_SPI_WRITE_N55P242(N55P_PCKAB,(N55P_SPI_READ_N55P242(N55P_PCKAB)|(u8Divider<<0)));
                break;
            case N55P_CKA_PA47:
                N55P_SPI_WRITE_N55P242(N55P_PCKAB,(N55P_SPI_READ_N55P242(N55P_PCKAB)|(u8Divider<<2)));
                break;
            case N55P_CKB_PB03:
                N55P_SPI_WRITE_N55P242(N55P_PCKAB,(N55P_SPI_READ_N55P242(N55P_PCKAB)|(u8Divider<<4)));                
                break;
            case N55P_CKB_PB47:
                N55P_SPI_WRITE_N55P242(N55P_PCKAB,(N55P_SPI_READ_N55P242(N55P_PCKAB)|(u8Divider<<6)));                
                break;
            case N55P_CKC_PC03:
                N55P_SPI_WRITE_N55P242(N55P_PCKCD,(N55P_SPI_READ_N55P242(N55P_PCKCD)|(u8Divider<<0)));                
                break;
            case N55P_CKC_PC47:
                N55P_SPI_WRITE_N55P242(N55P_PCKCD,(N55P_SPI_READ_N55P242(N55P_PCKCD)|(u8Divider<<2)));                
                break;            
        }
        return 0;
    }    
}

int8_t N55P_SetWakeupPort(uint8_t u8Port)//Need to set Input Pin first
{
    if(u8Port>=N55P__242_PORTAMOUNT)
        return -1;
    else
    {
        switch(u8Port)
        {
            case N55P__242_PA:
                N55P_SPI_WRITE_N55P242(N55P_WKCTL,(N55P_SPI_READ_N55P242(N55P_WKCTL)|0x40));//set KCAEN=1
                break;
            case N55P__242_PB:
                N55P_SPI_WRITE_N55P242(N55P_WKCTL,(N55P_SPI_READ_N55P242(N55P_WKCTL)|0x20));//set KCBEN=1                
                break;
            case N55P__242_PC:
                N55P_SPI_WRITE_N55P242(N55P_WKCTL,(N55P_SPI_READ_N55P242(N55P_WKCTL)|0x10));//set KCCEN=1                
                break;
        }
        return 0;
    }
}

void N55P_ClearWakeup(void)
{
    N55P_SPI_WRITE_N55P242(N55P_WKCTL,0x00);
}


void N55P_StartWakeup(void)
{
    N55P_SPI_READ_N55P242(N55P_PINA);
    N55P_SPI_READ_N55P242(N55P_PINB);
    N55P_SPI_READ_N55P242(N55P_PINC);
    N55P_SPI_WRITE_N55P242(N55P_WKCTL,(N55P_SPI_READ_N55P242(N55P_WKCTL)|0x80));
}

int8_t N55P_CheckWakeupSource(uint8_t u8Port)
{
    uint8_t u8SPIData;    
    if(u8Port>=N55P__242_PORTAMOUNT)
        return -1;
    else
    {
        switch(u8Port)
        {
            case N55P__242_PA:
                u8SPIData =    N55P_SPI_READ_N55P242(N55P_PINA);
            case N55P__242_PB:
                u8SPIData = N55P_SPI_READ_N55P242(N55P_PINB);
            case N55P__242_PC:
                u8SPIData = N55P_SPI_READ_N55P242(N55P_PINC);
        }
        
        return u8SPIData;
    }            
}

//////////////////////////////////////////////////////////////////////////
#ifdef DEBUG
#define N55P_ASSERT(expr)                                                          \
{                                                                             \
    if (expr)                                                                 \
    {                                                                         \
    }                                                                         \
    else                                                                      \
    {                                                                         \
        assert_nrf_callback((uint16_t)__LINE__, (uint8_t *)__FILE__);         \
    }                                                                         \
}
#else
#define N55P_ASSERT(expr)
#endif // DEBUG

static const uint8_t port_pin_regAddr[] = {N55P_PINA, N55P_PINB, N55P_PINC};
void N55P_ports_read(uint32_t start_port, uint32_t length, uint8_t * p_masks)
{
	N55P_ASSERT(start_port + length <= sizeof(port_pin_regAddr));
    while(length--)
    {
		*p_masks = N55P_SPI_READ_N55P242(port_pin_regAddr[start_port++]);
        p_masks++;
    }
}

uint32_t N55P_pin_read(uint32_t pin_number)
{
	uint8_t u8read;
    N55P_ASSERT(pin_number<(sizeof(port_pin_regAddr)*8));
	u8read = N55P_SPI_READ_N55P242(port_pin_regAddr[pin_number/8]);
    return ((u8read >> (pin_number%8)) & 1UL);
}

void N55P_pin_set(uint32_t pin_number)
{
    N55P_ASSERT(pin_number<(sizeof(port_pin_regAddr)*8));
    N55P_Set1PinHigh(pin_number/8, pin_number%8);
}

void N55P_pin_clear(uint32_t pin_number)
{
    N55P_ASSERT(pin_number<(sizeof(port_pin_regAddr)*8));
    N55P_Set1PinLow(pin_number/8, pin_number%8);
}

void N55P_pin_toggle(uint32_t pin_number)
{
	N55P_ASSERT(pin_number<(sizeof(port_pin_regAddr)*8));
	N55P_SPI_WRITE_N55P242(N55P_XBUFA+(pin_number/8),(0x01<<(pin_number%8)));//set Buffer.x ^= 1
}

void N55P_cfg_output(uint32_t pin_number)
{
	N55P_pin_clear(pin_number);
}

void N55P_cfg_input(uint32_t pin_number, int32_t pull_config)
{
	nrf_gpio_pin_pull_t nrf_pull_config = (nrf_gpio_pin_pull_t)pull_config;
	N55P_ASSERT(pin_number<(sizeof(port_pin_regAddr)*8));
	switch (nrf_pull_config)
	{
	case NRF_GPIO_PIN_NOPULL:
		N55P_Set1PinInputFloating(pin_number/8, pin_number%8);
		break;
	case NRF_GPIO_PIN_PULLDOWN:
		N55P_Set1PinInputPullLow(pin_number/8, pin_number%8);
		break;
	case NRF_GPIO_PIN_PULLUP:
		N55P_Set1PinInputPullHigh(pin_number/8, pin_number%8);
		break;
	default:
		break;
	}
}

#else
void N55P_ports_read(uint32_t start_port/*0~2*/, uint32_t length/*1~3*/, uint8_t * p_masks){}
uint32_t N55P_pin_read(uint32_t pin_number/*0~23*/) {return 0;}// return 0/1
void N55P_pin_set(uint32_t pin_number){}
void N55P_pin_clear(uint32_t pin_number){}
void N55P_pin_toggle(uint32_t pin_number){}
void N55P_cfg_output(uint32_t pin_number){}
void N55P_cfg_input(uint32_t pin_number, int32_t pull_config/*0:float,1:PL,2:PH*/){}

#endif // SPI_ENABLED

